from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, update, delete
from app.db.postgres import get_session
from app.models import EvaluationTemplate
from app.db.mongo import db
from app.schemas.template import (
    EvaluationTemplateCreate,
    EvaluationTemplateUpdate,
    EvaluationTemplateRead,
)


router = APIRouter(prefix="/evaluation-templates", tags=["evaluation-templates"])


@router.get("", response_model=list[EvaluationTemplateRead])
async def list_templates(session: AsyncSession = Depends(get_session)):
    res = await session.execute(select(EvaluationTemplate).order_by(EvaluationTemplate.created_at.desc()))
    return [EvaluationTemplateRead.model_validate(x) for x in res.scalars().all()]


@router.post("", response_model=EvaluationTemplateRead)
async def create_template(payload: EvaluationTemplateCreate, session: AsyncSession = Depends(get_session)):
    data = payload.model_dump()
    # duplicate check
    code = data.get("template_version_code")
    if code:
        exists = await session.execute(select(EvaluationTemplate).where(EvaluationTemplate.template_version_code == code))
        if exists.scalars().first():
            raise HTTPException(status_code=400, detail="template_version_code_exists")
    if not data.get("indicator_version_id"):
        data["indicator_version_id"] = None
    if not data.get("word_template_mongo_id"):
        data["word_template_mongo_id"] = None
    obj = EvaluationTemplate(**data)
    session.add(obj)
    await session.flush()
    await session.refresh(obj)
    await session.commit()
    return EvaluationTemplateRead.model_validate(obj)


@router.put("/{template_id}", response_model=EvaluationTemplateRead)
async def update_template(template_id: str, payload: EvaluationTemplateUpdate, session: AsyncSession = Depends(get_session)):
    obj = await session.get(EvaluationTemplate, template_id)
    if not obj:
        raise HTTPException(status_code=404, detail="template_not_found")
    data = payload.model_dump(exclude_unset=True)
    # optional duplicate check when changing template_version_code
    new_code = data.get("template_version_code")
    if new_code and new_code != obj.template_version_code:
        exists = await session.execute(select(EvaluationTemplate).where(EvaluationTemplate.template_version_code == new_code))
        if exists.scalars().first():
            raise HTTPException(status_code=400, detail="template_version_code_exists")
    if "indicator_version_id" in data and not data.get("indicator_version_id"):
        data["indicator_version_id"] = None
    if "word_template_mongo_id" in data and not data.get("word_template_mongo_id"):
        data["word_template_mongo_id"] = None
    for k, v in data.items():
        setattr(obj, k, v)
    await session.flush()
    await session.refresh(obj)
    await session.commit()
    return EvaluationTemplateRead.model_validate(obj)


@router.delete("/{template_id}")
async def delete_template(template_id: str, session: AsyncSession = Depends(get_session)):
    obj = await session.get(EvaluationTemplate, template_id)
    if not obj:
        raise HTTPException(status_code=404, detail="template_not_found")
    await session.delete(obj)
    await session.commit()
    return {"ok": True}


@router.get("/{template_id}", response_model=EvaluationTemplateRead)
async def get_template(template_id: str, session: AsyncSession = Depends(get_session)):
    obj = await session.get(EvaluationTemplate, template_id)
    if not obj:
        raise HTTPException(status_code=404, detail="template_not_found")
    return EvaluationTemplateRead.model_validate(obj)


@router.post("/{template_id}/clone", response_model=EvaluationTemplateRead)
async def clone_template(template_id: str, payload: EvaluationTemplateCreate, session: AsyncSession = Depends(get_session)):
    src = await session.get(EvaluationTemplate, template_id)
    if not src:
        raise HTTPException(status_code=404, detail="template_not_found")

    data = payload.model_dump()
    new_code = (data.get("template_version_code") or "").strip()
    if not new_code:
        raise HTTPException(status_code=400, detail="template_version_code_required")

    exists = await session.execute(select(EvaluationTemplate).where(EvaluationTemplate.template_version_code == new_code))
    if exists.scalars().first():
        raise HTTPException(status_code=400, detail="template_version_code_exists")

    if not data.get("indicator_version_id"):
        data["indicator_version_id"] = None
    if not data.get("word_template_mongo_id"):
        data["word_template_mongo_id"] = None

    obj = EvaluationTemplate(**data)
    session.add(obj)
    await session.flush()
    await session.refresh(obj)

    try:
        src_doc = await db.report_template_outline.find_one({"template_version_code": src.template_version_code})
        outline = (src_doc or {}).get("outline", [])
        await db.report_template_outline.update_one(
            {"template_version_code": obj.template_version_code},
            {"$set": {"template_version_code": obj.template_version_code, "outline": outline}},
            upsert=True,
        )
    except Exception as e:
        # 如果Mongo克隆失败，回滚Postgres新建
        await session.rollback()
        raise HTTPException(status_code=500, detail="clone_outline_failed")

    await session.commit()
    return EvaluationTemplateRead.model_validate(obj)
